#pragma once

#include <iostream>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Common.hpp"

using namespace log_ns;


class Mutiplexing
{
public:
    virtual bool AddEvent(int fd, uint32_t events) = 0;
    virtual int Wait(struct epoll_event *revs, int size, int timeout) = 0;
    virtual bool ModEvent(int fd, uint32_t events) = 0;
    virtual bool DelEvent(int fd) = 0;

};

class Epoller : public Mutiplexing
{
private:
    bool ModEventHelper(int fd, uint32_t events, int oper)
    {
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = events;
        int n = epoll_ctl(_epfd, oper, fd, &ev);
        if (n < 0)
        {
            LOG(FATAL, "epoll_ctl: fd:%d, events is %s failed\n", fd, EventsToString(events).c_str());
            return false;
        }
        LOG(INFO, "epoll_ctl: fd:%d, events is %s success\n", fd, EventsToString(events).c_str());
        return true;
    }
public:
    Epoller()
    {
        int fd = epoll_create(1);
        if (fd < 0)
        {
            LOG(FATAL, "epoll_create failed\n");
            exit(EPOLL_CREATE_ERROR);
        }
        // 创建 epoll 模型成功
        _epfd = fd;
    }

    std::string EventsToString(uint32_t events)
    {
        std::string eventstr;
        if (events & EPOLLIN)
            eventstr = "EPOLLIN";
        if (events & EPOLLOUT)
            eventstr += "|EPOLLOUT";
        if (events & EPOLLET)
            eventstr += "|EPOLLET";

        return eventstr;
    }

    bool AddEvent(int fd, uint32_t events) override
    {
        return ModEventHelper(fd, events, EPOLL_CTL_ADD);
    }

    bool ModEvent(int fd, uint32_t events) override
    {
        return ModEventHelper(fd, events, EPOLL_CTL_MOD);
    }

    int Wait(struct epoll_event *revs, int size, int timeout) override
    {
        return epoll_wait(_epfd, revs, size, timeout);
    }

    bool DelEvent(int fd) override
    {
        int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
        return n == 0;
    }

    ~Epoller()
    {

    }
private:
    int _epfd;
};